<?php
/**
 * Description:
 *
 * @author      Eden
 * @datetime    2017/1/1 18:51
 * @copyright   WuHan HuQi Technology Co.,Ltd.
 * @url         http://cnhuqi.com
 */
require_once FCPATH . '/application/third_party/wechat/include.php';

use Wechat\Loader;

class Wx extends CI_Controller
{

    private $pay_log = '';

    private $dateTime = '';

    private $options = [];

    private $sn = '';

    private $transaction_id = '';

    private $err = '';

    /**
     * 初始化
     */
    public function __construct()
    {
        parent::__construct();
        // 微信配置
        $this->options = $this->config->item('wechat');                   // 公众账号设置
        $this->pay_log = '/var/pay/Wechat-' . date('Y-m') . '.log';
        $this->dateTime = date('Y-m-d H:i:s');
    }

    public function index()
    {

    }

    /**
     * 充值回调
     */
    public function cashin()
    {
        $return = [
            'return_code' => 'FAIL',
            'return_msg' => ''
        ];
        Loader::config($this->options);
        $wechat = Loader::get('pay');
        $this->load->model('common/Pay_Model', 'pay');
        do {
            $res = $wechat->getNotify();
            if (!$res) {
                $return['return_msg'] = '鉴权失败';
                break;
            }

            file_put_contents($this->pay_log, '---------------------------------------------' . PHP_EOL, FILE_APPEND);
            // 1. 判断返回状态
            if ($res['return_code'] == 'SUCCESS') {
                if ($res['result_code'] == 'SUCCESS') {
                    $this->sn = value($res, 'out_trade_no');
                    $this->transaction_id = value($res, 'transaction_id', '');

                    // 2. 跟当前订单进行对比
                    $orderDb = clone($this->db);
                    $query = $orderDb->get_where('user_cashin_order', ['sn' => $this->sn]);
                    $row = $query->row_array();
                    if (empty($row)) {
                        $return['return_msg'] = '订单不存在';
                        file_put_contents($this->pay_log, $this->dateTime . " : " . $return['return_msg'] . PHP_EOL, FILE_APPEND);
                        file_put_contents($this->pay_log, var_export($res, true) . PHP_EOL, FILE_APPEND);
                        break;
                    }

                    $amount = intval($row['amount']);
                    if ($amount !== intval($res['total_fee'])) {
                        $return['return_msg'] = '金额不符';
                        file_put_contents($this->pay_log, $this->dateTime . " : " . $return['return_msg'] . PHP_EOL, FILE_APPEND);
                        file_put_contents($this->pay_log, var_export($res, true) . PHP_EOL, FILE_APPEND);
                        break;
                    }

                    if ($row['status'] == 6) {
                        $return['return_msg'] = '订单已支付';
                        file_put_contents($this->pay_log, $this->dateTime . " : " . $return['return_msg'] . PHP_EOL, FILE_APPEND);
                        file_put_contents($this->pay_log, var_export($res, true) . PHP_EOL, FILE_APPEND);
                        break;
                    }

                    if (!$this->afterCashIn($row, $res)) {
                        $return['return_msg'] = $this->err;
                        file_put_contents($this->pay_log, $this->dateTime . " : " . $return['return_msg'] . PHP_EOL, FILE_APPEND);
                        file_put_contents($this->pay_log, var_export($res, true) . PHP_EOL, FILE_APPEND);
                        break;
                    }

                    file_put_contents($this->pay_log, $this->dateTime . " 交易成功[用户充值] : SN=" . $row['sn'] . PHP_EOL, FILE_APPEND);
                    $return['return_code'] = 'SUCCESS';
                    $return['return_msg'] = 'OK';

                } else {
                    file_put_contents($this->pay_log, 'FAILED: ' . var_export($res, true) . PHP_EOL, FILE_APPEND);
                    $return['return_msg'] = value($res, 'err_code_des', '');
                }
            } else {
                file_put_contents($this->pay_log, 'FAILED: ' . var_export($res, true) . PHP_EOL, FILE_APPEND);
            }
        } while(false);

        $wechat->replyXml($return);
    }

    /**
     * 充值回调完成后
     * @param $order
     * @param $res
     * @return bool
     */
    protected function afterCashIn($order, $res)
    {
        $orderDB = clone($this->db);
        $orderDB->where('id', $order['id']);
        $orderDB->update('user_cashin_order', [
            'status' => 6,
            'transaction_id' => value($res, 'transaction_id', '')
        ]);

        if (!$orderDB->affected_rows()) {
            $this->err = '订单状态修改失败';
            return false;
        }

        // 增加账号余额，增加到用户冻结资产和总金额
        $userDB = clone($this->db);
        $userDB->where('id', $order['userid']);
        $userDB->set('amount', "amount+{$order['amount']}", false);
        $userDB->set('amountFreeze', "amountFreeze+{$order['amount']}", false);
        $userDB->update('user');

        $mealDB = clone($this->db);
        $mealDB->where('id', $order['mealid']);
        $mealDB->set('members', "members+1", false);
        $mealDB->update('cash_meal');

        return $userDB->affected_rows();
    }

    /**
     * 购买回调
     */
    public function notify()
    {
        $return = [
            'return_code' => 'FAIL',
            'return_msg' => ''
        ];

        Loader::config($this->options);
        $wechat = Loader::get('pay');
        $this->load->model('common/Pay_Model', 'pay');
        do {
            $res = $wechat->getNotify();
            if (!$res) {
                $return['return_msg'] = '鉴权失败';
                break;
            }

            file_put_contents($this->pay_log, '---------------------------------------------' . PHP_EOL, FILE_APPEND);
            // 1. 判断返回状态
            if ($res['return_code'] == 'SUCCESS') {
                if ($res['result_code'] == 'SUCCESS') {
                    $this->sn = value($res, 'out_trade_no');
                    $this->transaction_id = value($res, 'transaction_id', '');

                    // 2. 跟当前订单进行对比
                    $orderDb = clone($this->db);
                    $query = $orderDb->get_where('user_order', ['sn' => $this->sn]);
                    $order = $query->row_array();
                    if (empty($order)) {
                        $return['return_msg'] = '订单不存在';
                        file_put_contents($this->pay_log, $this->dateTime . ' : ' . $return['return_msg'] . PHP_EOL, FILE_APPEND);
                        file_put_contents($this->pay_log, var_export($res, true) . PHP_EOL, FILE_APPEND);
                        break;
                    }

                    $totalPrice = intval($order['totalPrice']);
                    if ($totalPrice != $res['total_fee']) {
                        $return['return_msg'] = '商品金额不符';
                        file_put_contents($this->pay_log, $this->dateTime . ' : ' . $return['return_msg'] . PHP_EOL, FILE_APPEND);
                        file_put_contents($this->pay_log, var_export($res, true) . PHP_EOL, FILE_APPEND);
                        break;
                    }

                    if ($order['payStatus'] == 6) {
                        $return['return_msg'] = '商品已支付';
                        file_put_contents($this->pay_log, $this->dateTime . ' : ' . $return['return_msg'] . PHP_EOL, FILE_APPEND);
                        file_put_contents($this->pay_log, var_export($res, true) . PHP_EOL, FILE_APPEND);
                        break;
                    }

                    // 3. 修改订单状态
                    $modifyData = [
                        'payWay' => 2,
                        'payStatus' => 6,
                        'status' => 'Pending'
                    ];
                    $orderDb2 = clone($this->db);
                    $orderDb2->where('sn', $this->sn);
                    $orderDb2->update('user_order', $modifyData);

                    if ($orderDb2->affected_rows()) {
                        file_put_contents($this->pay_log, $this->dateTime . ' : 订单编号 - ' . $order['sn'] . ' 支付成功' . PHP_EOL, FILE_APPEND);

                        // 分销提成,应该放在订单结束之后
                        $data['status'] = 6;
                        $data['transaction_id'] = value($res, 'transaction_id');
                        $this->pay->saveWxBuy($data, $this->sn);

                        $this->afterWxPay($order);

                        $return['return_code'] = 'SUCCESS';
                        $return['return_msg'] = 'OK';
                    }
                } else {
                    $return['return_msg'] = value($res, 'err_code_des', '');
                }
            } else {
                file_put_contents($this->pay_log, 'FAILED: ' . var_export($res, true) . PHP_EOL, FILE_APPEND);
            }
        } while(false);

        if (!empty($this->sn) && $return['return_code'] == 'FAIL') {
            $this->pay->saveWxBuy([
                'error_msg' => value($return, 'return_msg', ''),
                'error_code' => value($return, 'return_code', ''),
                'status' => 5,
                'transaction_id' => !empty($this->transaction_id) ? $this->transaction_id : ''
            ], $this->sn);
        }

        $wechat->replyXml($return);
    }

    // 微信支付成功后的处理逻辑
    protected function afterWxPay($order)
    {
        $this->_deduct($order);     // 提成
        $this->_stock($order);      // 减库存
        $this->_score($order);      // 加积分
        // $this->_amount($order);     // 处理资金
    }


    /**
     * 加积分
     * @param $order
     * @return bool
     */
    private function _score($order)
    {
        // 根据交易金额订单积分，1元1个积分
        $amount = floor(($order['goodsPrice'] + $order['expressPrice']) / 100);
        if ($amount <= 0) {
            return false;
        }

        $userdb = clone($this->db);
        $userdb->where('id', $order['userId']);
        $userdb->set('score', "score+{$amount}", false);
        $userdb->update('user');
    }

    /**
     * 处理库存
     * @param $order
     */
    private function _stock($order)
    {
        // 减库存
        $db = clone($this->db);
        $goodsDB = clone($this->db);
        $q = $db->get_where('user_order_goods', ['orderId' => $order['id']]);
        $goods = $q->result_array();
        $rdb = clone($this->db);
        foreach ($goods as $good) {
            $rdb->set('stock', "stock-{$good['num']}", false);
            $rdb->set('soledStock', "soledStock+{$good['num']}", false);
            $rdb->where(['id' => $good['ruleId']]);
            $rdb->update('base_goods_rule');

            // 减总库存
            $goodsId = $order['goodsId'];
            $goodsDB->where('id', $goodsId);
            $goodsDB->set("stock", "stock-{$good['num']}", false);
            $goodsDB->set("sold", "sold-{$good['num']}", false);
            $goodsDB->update('base_goods');
        }
    }

    /**
     * 提成
     * @param $order
     * @return bool
     */
    public function _deduct($order)
    {
        // 上级
        $user = $this->_getUser($order['userId']);
        if (empty($user)) {
            return false;
        }

        // 交易金额,单位分
        $amounts = $order['goodsPrice'] + $order['expressPrice'];

        // 设置
        $scale = $this->_getSetting();

        $puserid = $user['puserid'];
        $ppuserid = $user['ppuserid'];

        if (!empty($puserid) && !empty($scale['level_1'])) {
            // 上级提成
            do {
                $deduct = floor($amounts * $scale['level_1']);
                if (empty($deduct)) { break; }

                $pUserDb = clone($this->db);
                $pUserDb->where(['id' => $puserid]);
                $pUserDb->set('amount', 'amount+' . $deduct, false);
                $pUserDb->set('amountUnLimit', 'amountUnLimit+' . $deduct, false);
                $pUserDb->update('user');
                $this->_saveDeduct($order['userId'], $puserid, $ppuserid, $deduct, $order['id']);
                unset($deduct);
            } while(0);
        }

        if (!empty($ppuserid) && !empty($scale['level_2'])) {
            // 上上级
            do {
                $deduct = floor($order['goodsPrice'] * $scale['level_2']);
                if (empty($deduct)) {
                    break;
                }

                $ppUserDb = clone($this->db);
                $ppUserDb->where(['id' => $ppuserid]);
                $ppUserDb->set('amount', 'amount+' . $deduct, false);
                $ppUserDb->set('amountUnLimit', 'amountUnLimit+' . $deduct, false);
                $ppUserDb->update('user');
                $this->_saveDeduct($order['userId'], $puserid, $ppuserid, $deduct, $order['id']);
                unset($deduct);
            } while(0);
        }
    }

    private function _saveDeduct($userid, $puserid = 0, $ppuserid = 0, $amount = 0, $orderid = 0)
    {
        $db = clone($this->db);
        $db->insert('user_wx_deduct_record', [
            'userid' => $userid,
            'puserid' => $puserid,
            'ppuserid' => $ppuserid,
            'orderid' => $orderid,
            'amount' => $amount,
            'created' => dateTime()
        ]);
    }

    /**
     * 用户关系
     * @param $userId
     * @return mixed
     */
    private function _getUser($userId)
    {
        $db = clone($this->db);
        $q = $db->get_where('user_wx_relationship', ['userid' => $userId]);
        $row = $q->row_array();
        return $row;
    }

    /**
     * 获取比例设置
     * @return array
     */
    private function _getSetting()
    {
        $db = clone($this->db);
        $q = $db->get_where('setting', ['use' => 'wx', 'key' => 'scale']);
        $row = $q->row_array();

        $data = [
            'level_1' => 0,
            'level_2' => 0
        ];

        if ($row) {
            $value = json_decode($row['value'], true);
            $data['level_1'] = !empty($value['level_1']) ? doubleval($value['level_1']) : 0;
            $data['level_2'] = !empty($value['level_2']) ? doubleval($value['level_2']) : 0;
        }
        return $data;
    }
}